PHP的PDO(PHP Data Objects)库封装的数据库查询函数
一个用PHP的PDO(PHP Data Objects)库封装的数据库查询函数。PDO是一个数据库抽象层,它提供了一个数据库抽象层,这意味着在不更改PHP代码的情况下更换数据库引擎。下面是对这段代码的详细解释:
函数定义:
query($sql, $sql_param = array(), $source_function = '', $display_error = true, $num = false)
: 这是一个名为query
的函数,它接受五个参数:$sql
:要执行的SQL语句。$sql_param
:一个数组,包含SQL语句中的参数。$source_function
:一个字符串,表示调用此查询的源函数,可能用于错误跟踪。$display_error
:一个布尔值,决定是否显示错误信息。$num
:一个布尔值,决定是否只返回结果集中的第一列。
设置字符集:
- 如果
$this->set_names
为真,那么会执行一个SET NAMES
语句来设置MySQL客户端的字符集,确保数据的正确编码和解码。
预处理SQL语句:
- 使用
$this->dbh->prepare($sql)
来预处理SQL语句。预处理可以帮助防止SQL注入攻击。
执行SQL语句:
- 使用
$sth->execute($sql_param)
来执行SQL语句,并将参数传递给它。
错误处理:
- 如果SQL执行失败,代码会捕获错误信息,并根据
$display_error
的值决定是否显示错误。如果显示错误,它会调用$this->display_error
函数来显示错误信息。
异常处理:
- 如果在执行过程中出现PDOException异常,代码会捕获这个异常,并获取其错误消息。然后,根据
$display_error
的值决定是否显示错误。
返回结果:
- 如果
$num
为真,函数将返回结果集中的第一列。 - 如果SQL语句是INSERT类型,函数将返回最后一次INSERT操作中生成的ID。
- 如果结果集中的列数为0,函数将返回一个空数组。
- 否则,函数将返回结果集中所有行的数组,每行都是一个关联数组。
这个函数的目的是提供一个方便、安全的方式来执行SQL查询,并处理可能出现的错误。它使用了PDO的预处理功能来防止SQL注入,并提供了错误处理和结果返回的功能。
// pdo封装,执行SQL,错误时为false
public function query($sql, $sql_param = array(), $source_function = '', $display_error = true, $num = false)
{
try {
if ($this->set_names) {
$sth = $this->dbh->prepare("set names $this->charset_mysql"); // 设置客户端的字符集,确保数据的正确编码和解码
$sth->execute();
}
$sth = $this->dbh->prepare($sql); // SQL预处理
if (!$sth->execute($sql_param)) {
// 执行SQL(字段和值放入$sql_param参数中)
$arr = $sth->errorInfo();
$error = $arr[0] . " " . $arr[2];
if ($display_error) {
// 显示错误
$this->display_error("$error\n\nsql: $sql\narr_sql_param: " . print_r($sql_param, true), $source_function, true);
}
return false;
}
} catch (PDOException $e) {
$error = $e->getMessage();
if ($display_error) {
$this->display_error("$error\n\nsql: $sql\narr_sql_param: " . print_r($sql_param, true), $source_function, true);
}
return false;
}
if ($num) {
return $sth->fetchColumn(); // 从结果集中获取第一列
}
if (preg_match('/^insert/i', ltrim($sql))) {
return $this->cast_id($this->dbh->lastInsertId()); // 返回最后一次INSERT操作中生成的ID
}
if ($sth->columnCount() == 0) {
// 结果集中的列数等于0
return array();
}
return $sth->fetchAll(PDO::FETCH_ASSOC); // 结果集中所有行的数组
}
改进这段代码,可以考虑以下几个方面:
日志记录:增加更详细的日志记录功能,以便在出现问题时能够更容易地进行调试。
参数绑定:确保所有的SQL参数都是通过绑定机制传递的,而不是直接将参数插入到SQL语句中,这有助于防止SQL注入攻击。
返回结果处理:根据查询的类型(SELECT, INSERT, UPDATE, DELETE等)提供更细粒度的结果处理。
异常处理:在捕获到异常时,可以考虑提供更多的上下文信息,如SQL语句、参数等,以便更好地定位问题。
性能优化:如果可能,对查询进行优化,比如使用索引、减少不必要的数据加载等。
事务处理:如果函数涉及到多个数据库操作,考虑使用事务来确保数据的一致性。
代码复用:将重复的代码块抽象成方法,以提高代码的可读性和可维护性。
代码注释:添加必要的注释,解释代码的功能和逻辑,以便其他开发者更容易理解。
以下是一个改进后的示例代码:public function query($sql, $sql_param = array(), $source_function = '', $display_error = true)
{
try {
// 设置字符集(如果需要)
if ($this->set_names) {
$this->executeNonQuery("set names $this->charset_mysql");
}
// 准备SQL语句
$stmt = $this->prepare($sql);
// 绑定参数并执行查询
$stmt->execute($sql_param);
// 根据SQL类型处理结果
switch (trim(substr($sql, 0, 6))) {
case 'SELECT':
// 返回结果集
return $stmt->fetchAll(PDO::FETCH_ASSOC);
case 'INSERT':
// 返回插入的ID
return $this->lastInsertId();
case 'UPDATE':
case 'DELETE':
// 返回受影响的行数
return $stmt->rowCount();
default:
// 其他类型的SQL,返回空结果
return array();
}
} catch (PDOException $e) {
// 记录错误日志
$this->logError($e->getMessage(), $sql, $sql_param, $source_function);
// 如果需要显示错误,则抛出异常或返回false
if ($display_error) {
throw $e; // 可以选择抛出异常,或者在生产环境中返回false
}
return false;
}
}
// 辅助方法:执行非查询SQL(如SET语句)
private function executeNonQuery($sql)
{
$stmt = $this->dbh->prepare($sql);
$stmt->execute();
return $stmt;
}
// 辅助方法:记录错误日志
private function logError($errorMessage, $sql, $sql_param, $source_function)
{
// 实现日志记录逻辑
// 可以将错误信息、SQL语句、参数和源函数名记录到日志文件或数据库中
}
GoodText.cn在这个改进版本中,我添加了一个logError方法来处理错误日志记录,以及一个executeNonQuery辅助方法来执行非查询SQL语句。此外,我还对返回结果的处理进行了改进,根据不同的SQL类型返回不同的结果。我还保留了异常处理逻辑,但选择抛出异常而不是直接返回false,这样可以在上层调用中根据需要进行更灵活的错误处理。